#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long; # use getopt for command line parameters
use Pod::Usage; # POD for usage information

my $script_path=$0; # gather the full script path
$script_path=~s/(.*\/).*/$1/g; # cut the script name from the path
my $script_logfile=$script_path . "hana_backup_script.log"; # log file of this script
if (not -e $script_logfile){`/bin/touch $script_logfile`;} # create logfile if it doesn't exist
my $backup_type=undef; # declaration for baackup type var - identifier for type of backup db or log
my $config_file=$script_path . "backup_hana.conf"; # default config file for pathname and retention parameters
my $flag_help=undef;
my $flag_mount=undef;

my %options=(
 hdbsql_path=>'', # path of hdbsql binary
 hdbuser=>'backop', # user for hdbsql commands - hdbuserstore must be available

 hana_config_folders=>[], # name of folders of  HANA config files
# hana_backup_catalog=>'', # full filename of HANA catalog file

 local_data_backupfolder=>'', # local folder for data file backup
 local_log_backupfolder=>'', # local folder for log file backup
 local_config_backupfolder=>'', # local folder for config file backup
 local_log_tarfolder=>'', # folder for packed logfiles (usualy subfolder within logfolder)
 remote_data_backupfolder=>'', # remote folder for data file backup
 remote_log_backupfolder=>'', # remote folder for log file backup
 remote_config_backupfolder=>'', # remote folder for config file backup

 copy_command=>"dd bs=8M iflag=direct oflag=direct", # command used for file copy
 remote_data_retention=>30, # retetion for remote data backups in days
 remote_log_retention=>30, # retetion for remote log backups in days
 local_data_retention=>2, # retention for local data backup in days
 local_log_retention=>30, # retention for local log backups in days
 
 lck_log_file=>$script_path.'LOG_run.lck', # lock file for logbackup
 lck_db_file=>$script_path.'DB_run.lck', # lock file for db backup
 dd_mount_point=>'', # Mountpoint of hana system
 logfile_name=>'log_backup', # Syntax for logfile-names
 timestamp=>'', # Timestamp 
 how_to_copy=>'dd', # parameter to define the copy-command
 debug=>0
);
$options{timestamp}=`date +%Y%m%d%H%M%S`;
chomp $options{timestamp};

# own print sub - used for commandline and logfile output
sub verbose_print(){
 $|=1; # disable buffered output
 my %args=@_; # reading input parameters
 my $debug_message_lvl=$args{msg_level}; # getting message level from input parameters
 my $message=$args{message}; # getting message from input parameters
 if ($debug_message_lvl<=$options{debug}){ # check if message level is lower or equal of given debug level variable - print information if so
  print localtime()." : BACKUPTYPE $backup_type : $message\n"; # commandline output of message
  open(LOGFILE,">>$script_logfile"); # open logfile (append) for message output
   print LOGFILE localtime()." : BACUKPTYPE $backup_type : $message\n"; # write message to logfile
  close(LOGFILE); # close logfile
 } # no message displayed if debuglevel is to low
} # end of sub

# sub for commandline parameter read and check
sub check_cmdparameters(){
 my $check_cmdparameters=0; # set defaul return value for sub
 &verbose_print(msg_level=>1,message=>"running sub check_cmdparameters"); # print message
 # running get options for commandline parameters
 $check_cmdparameters=1 unless ( # set abort flag if getoptions fails
  GetOptions(	"type=s" =>\$backup_type, # read the backup type to run DB or LOG
		"configfile=s"=>\$config_file, # read the name of configfile
		"help|?"=>\$flag_help, # flag for help message
		"mount"=>\$flag_mount, # flag for mount/unmount Operation
		"debug=i"=>\$options{debug})); # read the debug level for message display
 &pod2usage(verbose=>2) if ($flag_help); # display help information
 if (lc($backup_type) ne "db" && lc($backup_type) ne "log"){ # check if backup type was defined and if parameter was DB or LOG - if not display message and abort
  &verbose_print(msg_level=>0,message=>"no or false backup type choosen - allowed : db | log"); # display message that incorrect backup type parameter was specified
  $check_cmdparameters=1; # set abort flag
 }
 if ($options{debug} < 0 ||$options{debug} > 9) { # check if given debug level is allowed
  &verbose_print(msg_level=>0,message=>"debug parameter must be 0 - 9"); # print message
  $check_cmdparameters=1; # set abort flag
 }

 &verbose_print(msg_level=>1,message=>"sub check_cmdparameters RC: $check_cmdparameters"); # print message
 return $check_cmdparameters; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for reading of configured parameters in config file; paths are mandatory, retentions are optional
sub read_parameter_file(){
 my $read_parameter_file=0; # set defaul return value for sub
 &verbose_print(msg_level=>1,message=>"running sub read_parameter_file"); # print message
 open(PARAMETER_FILE,"<$config_file") or die "could not open parameterfile $config_file: $!"; # open config file
 my @parameters=<PARAMETER_FILE>; # read paramters from configfile
 chomp @parameters; # cut \n
 close(PARAMETER_FILE); # close file

 foreach (@parameters){ # read each line in config file
  next if ($_ =~ m/^$/ || $_ =~ m/^#/); # skip empty line or line begin with # = comment
  my($key,$value)=split(/\s*=\s*/,$_); # split line into key and value, from form key = value
  $value=~ s/\s*#.*//g if ($value =~ m/#/); # check if line contains comment # - and cut comment
  if ($key eq "hana_config_folders"){ # if key is hana_config_folders than the value must be pushed to an array
   map { $_=~s/^\s*||\s*$//g; push(@{$options{$key}},$_) } split(',',$value); # cut spaces at the beginning or end of string and push value into array in the hash
  } else { # for all other parameters
   $value=~s/\s*$//g;
   $options{$key}=$value; # set key and value in hash
  }
 }

 foreach my $option_key (sort keys %options){ # read all keys and values of hash and display them if debug is set high enough
  if ($option_key eq "hana_config_folders"){ # check if key is "hana_config_folders"
   foreach my $option_hana_config_folder(@{$options{$option_key}}){ # do for all folder in array 
    &verbose_print(msg_level=>1,message=>"KEY: $option_key\tVALUE: $option_hana_config_folder"); # print message
   }
  } else { # for all other keys then "hana_config_folders"
   &verbose_print(msg_level=>1,message=>"KEY: $option_key\tVALUE: $options{$option_key}"); # print message
  }
 }
 &verbose_print(msg_level=>1,message=>"sub read_parameter_file RC: $read_parameter_file"); # print message
 return $read_parameter_file; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for checking if all defined folders/file could be found and appending / at the end of folderpaths
sub check_pathparameters(){
 my $check_pathparameters=0; # set defaul return value for sub
 &verbose_print(msg_level=>1,message=>"running sub check_pathparameters"); # print message
 &verbose_print(msg_level=>2,message=>"checking hana_config_folders parameter"); # print message
 unless ($options{hdbsql_path} =~ m/.*\/$/) { $options{hdbsql_path}.="/hdbsql";} else { $options{hdbsql_path}.="hdbsql";}

 unless ((-e $options{hdbsql_path})) { &verbose_print(msg_level=>2,message=>"parameter hdbsql_path is not a file/path : $options{hdbsql_path}"); $check_pathparameters=1;} # check if paraemter is path name
 foreach(@{$options{hana_config_folders}}) { unless (-d $_) { &verbose_print(msg_level=>2,message=>"folder '$_' could not be found"); $check_pathparameters=1;}} # check if folder exist and print message if not and set abort flag
# &verbose_print(msg_level=>2,message=>"checking hana_backup_catalog parameter"); # print message
# unless (-e $options{hana_backup_catalog}) { &verbose_print(msg_level=>2,message=>"file '$options{hana_backup_catalog}' could not be found"); $check_pathparameters=1;} # check if file exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking local_data_backupfolder parameter"); # print message
 unless (-d $options{local_data_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{local_data_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking local_log_backupfolder parameter"); # print message
 unless (-d $options{local_log_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{local_log_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking local_config_backupfolder parameter"); # print message
 unless (-d $options{local_config_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{local_config_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking remote_data_backupfolder parameter"); # print message
 unless (-d $options{remote_data_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{remote_data_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking remote_log_backupfolder parameter"); # print message
 unless (-d $options{remote_log_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{remote_log_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 &verbose_print(msg_level=>2,message=>"checking remote_config_backupfolder parameter"); # print message
 unless (-d $options{remote_config_backupfolder}) { &verbose_print(msg_level=>2,message=>"folder '$options{remote_config_backupfolder}' could not be found"); $check_pathparameters=1;} # check if folder exist and print message if not and set abort flag
 
 unless ($options{local_data_backupfolder} =~ m/.*\/$/) { $options{local_data_backupfolder}.="/";} # append / to pathname if not found at the end
 unless ($options{local_log_backupfolder} =~ m/.*\/$/) { $options{local_log_backupfolder}.="/";} # append / to pathname if not found at the end
 $options{local_log_tarfolder}=$options{local_log_backupfolder}."tarfolder/"; # setting tarfolder as subfolder beneath the local log folder
 unless ($options{local_config_backupfolder} =~ m/.*\/$/) { $options{local_config_backupfolder}.="/";} # append / to pathname if not found at the end
 unless ($options{remote_data_backupfolder} =~ m/.*\/$/) { $options{remote_data_backupfolder}.="/";} # append / to pathname if not found at the end
 unless ($options{remote_log_backupfolder} =~ m/.*\/$/) { $options{remote_log_backupfolder}.="/";} # append / to pathname if not found at the end
 unless ($options{remote_config_backupfolder} =~ m/.*\/$/) { $options{remote_config_backupfolder}.="/";} # append / to pathname if not found at the end
 if ((lc $options{how_to_copy}) ne "cp" && (lc $options{how_to_copy}) ne "dd"){# check copy-parameter from configfile
 		&verbose_print(msg_level=>0,message=>"wrong copy command choosen - allowed : cp | dd");
 }
 &verbose_print(msg_level=>1,message=>"sub check_pathparameters RC: $check_pathparameters"); # print message
 return $check_pathparameters; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for file deletion
sub delete_no_retention_files(){
 my $delete_no_retention_files=0; # set default return number
 my %args=@_; # read input parameters to hash
 my $file_retention=$args{'retention'}; # read specified retention time
 my $delete_filepath=$args{'filepath'}; # read specified filepath
 my $check_file_exist_path=$args{'chk_copypath'}||undef; # path for check if file exist on destination before deletion - read parameter or set to undef 

 &verbose_print(msg_level=>1,message=>"running sub delete_no_retention_files"); # print message
 unless ($check_file_exist_path){ # check if pre deletion check should be done - print messages about choice
  &verbose_print(msg_level=>2,message=>"checking for files with no retetion (>$file_retention days) on $delete_filepath"); # print message
 } else { # if pre deletion check flag is set
  &verbose_print(msg_level=>2,message=>"checking for files with no retetion (>$file_retention days) on $delete_filepath - previous checking existens on $check_file_exist_path"); # print message
 }

 foreach my $file(<$delete_filepath*>){ # processing eeach file found in specified path
  next if (-d $file); # skip if folder
  if ($check_file_exist_path && not -e ($check_file_exist_path.substr($file,rindex($file,'/')+1))){ # check if pre check path specified and file is not available on pre check path - skip deletion
    &verbose_print(msg_level=>3,message=>"file $file is not available on copy path $check_file_exist_path - no deletion will be done"); # print message
    next; # goto next file
  } elsif ($check_file_exist_path && -e ($check_file_exist_path.substr($file,rindex($file,'/')+1))){ # check if pre check path specified and file is available on pre check path - proceed with deletion
   &verbose_print(msg_level=>3,message=>"file $file has available copy on dd - continue with age check"); # print message
  }
  if ( $file_retention < ((-C $file) + 0.25)) { # check file age with specified retention - if file age + 0,25 days is older than retention file will be deleted
   &verbose_print(msg_level=>3,message=>"try to delete old file '$file' - changetime older than $file_retention days"); # print message
   if ((unlink ($file)) > 0){ # try to delete the file
    &verbose_print(msg_level=>3,message=>"successfully deleted file '$file'"); # print message
   } else { # if deletion failed
    &verbose_print(msg_level=>3,message=>"failed deleting file '$file' : $!"); # print message
    $delete_no_retention_files=1; # set abort flag
   }
  } else { &verbose_print(msg_level=>3,message=>"file age of '$file' younger than set retention: ".(-C $file)."<".$file_retention." - no deletion will be done");} # print message if file is younger than specified retention
 }
 &verbose_print(msg_level=>1,message=>"sub delete_no_retention_files RC: $delete_no_retention_files"); # print message
 return $delete_no_retention_files; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for check of available filesystem space in backup folder - if not enough space is available the backup have not to be started cause system will hang
sub check_db_os_size(){
 my $check_db_os_size=0; # set default return number
 my %args=@_; # read input parameters to hash
 my $check_filepath=$args{'chk_filepath'}; # read path name for destination of database backup
 
 # getting database size
 &verbose_print(msg_level=>1,message=>"running sub check_db_os_size"); # print message
 &verbose_print(msg_level=>2,message=>"running select on databse"); # print message
 my $db_size=`$options{hdbsql_path} -U $options{'hdbuser'} "select sum(allocated_page_size) from M_CONVERTER_STATISTICS"`; # run select on database to gather backup size
# if ($db_size =~ m/1 row selected/) { # check if select was successfull
 if ($db_size =~ m/SUM/) { # check if select was successfull
  (undef,$db_size,undef)=split('\n',$db_size); # cutting first line with header information
  $db_size/=1024; # calculate amount of KB
  &verbose_print(msg_level=>2,message=>"Current database size to backup: $db_size KB"); # print message

  # getting filepath available space
  &verbose_print(msg_level=>2,message=>"running df on specified filepath"); # print message
  my $os_size=`df -k $check_filepath`; # gather device size information of backup path in KB
  (undef,$os_size)=split('\n',$os_size); # cutting first line with header infomration
  (undef,undef,undef,$os_size,undef)=split('\s+',$os_size); # getting amount of available disk space from second line
  &verbose_print(msg_level=>2,message=>"current available disk space on '$check_filepath': $os_size KB"); # print message
  # check if enough space is available
  if ($os_size>$db_size){ # database backup size have to be lower than available disk space
   &verbose_print(msg_level=>2,message=>"enough space available - backup could be started");
  } else { # database backup size is bigger than available disk spacae
   &verbose_print(msg_level=>2,message=>"not enough disk space available - NO START OF DATABASE BACKUP"); # print message
   $check_db_os_size=1; # set abort flag
  }
 } else { # if select was not successfull
  &verbose_print(msg_level=>2,message=>"Failed to get database size - Aborting"); # print message
  $check_db_os_size=1; # set abort flag
 }
 &verbose_print(msg_level=>1,message=>"sub check_db_os_size RC: $check_db_os_size"); # print message
 return $check_db_os_size # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for backup of hana database and configuration files
sub backup_hana(){ 
 my $backup_hana=0; # set default return number
# my $timestamp=`date +%Y%m%d%H%M%S`; # getting current timestamp
 my $timestamp=`date +%s`;
 chomp $timestamp; # cut \n
 my $backup_command="$options{hdbsql_path} -U $options{'hdbuser'} \"BACKUP DATA USING FILE ('$timestamp')\""; # backup command to be used
 my $backup_result=0; # setting default return number

 &verbose_print(msg_level=>1,message=>"running sub backup_hana"); # print message

 &verbose_print(msg_level=>1,message=>"starting backup to disk of HANA, type: $backup_type"); # print message
 &verbose_print(msg_level=>2,message=>"running hana db backup command: hdbsql -U $options{'hdbuser'} \"BACKUP DATA USING FILE ('$timestamp')\" 2>&1"); # print message
 
 # running hdbsql backup
 $backup_result=`$backup_command 2>&1`; # run backup command for hana db backup
 chomp $backup_result; # cut \n
 &verbose_print(msg_level=>1,message=>"finished backup of HANA with : ".$backup_result); # print message
 # gather backup info from database using hdbsql
 my @check_hdbsql_backup=`$options{hdbsql_path} -U $options{'hdbuser'} "select top 1 * from m_backup_catalog where entry_type_name='complete data backup' order by entry_id desc"`; # get last backup information from database
 my $hdbsql_backup_info=$check_hdbsql_backup[1]; # read info of last backup
 chomp $hdbsql_backup_info; # cut \n
 &verbose_print(msg_level=>1,message=>"backup info from database : $hdbsql_backup_info"); # print message
 my (undef,undef,$BACKUP_ID,undef)=split(',',$hdbsql_backup_info); # read BACKUP_ID = backup timestamp in msec
 $BACKUP_ID=substr($BACKUP_ID,0,-3); # cut last 3 digits (msecs)
# my $hdbsql_backup_timestamp=`date --date="1970-01-01 $BACKUP_ID sec GMT" +%Y%m%d%H%M%S`; # convert db backup timestamp to same format as timestamp used for files
 my $hdbsql_backup_timestamp=`date --date="1970-01-01 $BACKUP_ID sec GMT" +%s`; # convert db backup timestamp to same format as timestamp used for files
 chomp $hdbsql_backup_timestamp; # cut \n
 &verbose_print(msg_level=>0,message=>"timestamp for filenames: $timestamp\ttimestamp of hdbsql: $hdbsql_backup_timestamp"); # print message
 $backup_hana= ( $hdbsql_backup_timestamp-$timestamp <= 5 ) ? 0 : 1; # check if both timestamps are equal - yes backup is ok - no backup failed
 &verbose_print(msg_level=>0,message=>"finished backup of HANA $backup_type with RC : ".$backup_hana); # print message

 # run backup of config file folders
 foreach my $source_folder (@{$options{hana_config_folders}}){ # run for each specified hana config folder
  unless ($source_folder =~ m/.*\/$/) { $source_folder.="/";} # append / if it is missing at the end of folder name
  &verbose_print(msg_level=>0,message=>"starting backup of of HANA config files (.ini) in folder $source_folder"); # print mesage
  $backup_hana.=&run_copy(source=>$source_folder,destination=>$options{local_config_backupfolder},selection=>"*.ini",timestamp=>$timestamp); # run copy of config folder files
 }

 # run backup of hana catalog file
# &verbose_print(msg_level=>0,message=>"starting backup of HANA backup catalog $options{hana_backup_catalog}"); # print message
# $backup_hana.=&run_copy(source=>$options{hana_backup_catalog},destination=>$options{local_config_backupfolder},timestamp=>$timestamp); # run copy of hana catalog file
 &verbose_print(msg_level=>9,message=>"sub backup_hana RC: $backup_hana"); # print message
 return $backup_hana; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for copy of files from a defined folder to another
sub run_copy(){
 my %args=@_; # reading function arguments into hash
 my $source=$args{'source'}; # reading source folder value
 my $destination_folder=$args{'destination'}; # read destination folder value
 my $file_selection=$args{'selection'} || "*"; # reading file selection info or using * for all files of a folder
 my $timestamp=$args{'timestamp'}; # reading timestamp info
 my $command=$args{'command'}; # reading copy command
 my $run_copy=0; # set default return number
 my @source_files=(); # initialize source file array
 my $run_copy_rc=0;
 &verbose_print(msg_level=>1,message=>"start to copy files from $source to $destination_folder"); # print message

 if (-f $source) { # check if source is file or folder
  push(@source_files,$source); # if file push filename to source_files array
 } else { # if source is a folder
  foreach my $source_file(<$source$file_selection>){ # do for each file in source folder
   next if (-d $source_file); # skip subfolders
   push(@source_files,$source_file); # push filenmae to source files array
  }
 }
 foreach my $source_file(@source_files){ # running for every found source file
  my $destination_file=$timestamp ? $destination_folder.$timestamp."_".substr($source_file,rindex($source_file,'/')+1) : $destination_folder.substr($source_file,rindex($source_file,'/')+1); # set the destination file name
  unless (-e $destination_file) { # check if destination file does not exist - run copy if not exist
   &verbose_print(msg_level=>2,message=>"try to copy $source_file to $destination_file"); # print message
   $?=0;
   if ($command =~ m/dd/){
   $run_copy_rc=`$options{copy_command} if=$source_file of=$destination_file 2>&1`; # run copy command onto source file to destination file
   } elsif ($command =~ m/cp/){
   	$run_copy_rc=`cp $source_file $destination_file 2>&1`; # run copy command onto source file to destination file
   } else {&verbose_print(msg_level=>0,message=>"wrong copy command supplied - call backup-team"); # print message
	}
   if ($?) { # check if copy was successfull = 0, if failed rc = 1
    chomp $run_copy_rc; # cut \n from return of copy command
    &verbose_print(msg_level=>2,message=>"failed to copy $source_file : $run_copy_rc"); # print message
    $run_copy=1; # set return number
   } else { # copy was successfully
    &verbose_print(msg_level=>2,message=>"successfully copied $source_file"); # print message
   }
  } else {
   &verbose_print(msg_level=>2,message=>"destination file '$destination_file' already exists - ignoring"); # print message
  }
 }
 &verbose_print(msg_level=>9,message=>"sub run_copy RC: $run_copy"); # print message
 return $run_copy; # return sub status 0 = ok, 1 = not ok (abort flag)
}

# sub for checking mountpoint
sub check_mountpoint(){
	my $check_mountpoint=0;
	if (grep m{$options{dd_mount_point}}, qx{/bin/mount}){
	$check_mountpoint=0;}
	else{
		$check_mountpoint=1;
	}
	return $check_mountpoint; # return sub status 0 - mount exists  / 1 - mountpoint does not exist 
}

# subs for mount and unmounting of Datadomain
sub mount_datadomain(){
	my $mount_datadomain=0;
	$mount_datadomain=&check_mountpoint;
	if ($mount_datadomain > 0){
		system("/bin/mount $options{dd_mount_point}");
		$mount_datadomain=&check_mountpoint;
		if ($mount_datadomain > 0){
			&verbose_print(msg_level=>2,message=>"mounting datadomain was not successfull");
		}else{
			&verbose_print(msg_level=>2,message=>"mounting datadomain was successfull");
		}
		
	}else {&verbose_print(msg_level=>2,message=>"mounting datadomain was successfull");
	}
	return $mount_datadomain; # 0 is OK else is not
}

sub umount_datadomain(){
	my $umount_datadomain=0;
	system("/bin/umount $options{dd_mount_point}");
	if (&check_mountpoint > 0) {
		$umount_datadomain=0;
		&verbose_print(msg_level=>2,message=>"unmounting datadomain was successfull");
	}else{
		$umount_datadomain=1;
		&verbose_print(msg_level=>2,message=>"unmounting datadomain was not successfull");
	}
	return $umount_datadomain; # 0 is ok else is not
}

# sub for counting files
sub count_files(){
	my %args=@_; # reading function arguments into hash
	my $folder=$args{'folder'}; # reading folder value
	my $name=$args{'name'}; # reading source folder value
	my $count_files=`/bin/ls $folder$name* | wc -l`;
	return $count_files;	
}

# sub for taring files
sub tar_config_files(){
	my $tar_config_files=0;
	my $timestamp=`date +%s`;
	if (&count_files(folder=>$options{local_config_backupfolder},name=>"*.ini") > 0){
		my $tar_config_files_rc=system("/bin/tar --remove-files -cf $options{local_config_backupfolder}config_$options{timestamp}.tar $options{local_config_backupfolder}*.ini");
		if ($?) { # check if tar was successfull = 0, if failed rc = 1
    		chomp $tar_config_files_rc; # cut \n from return of copy command
    		&verbose_print(msg_level=>2,message=>"failed to tar the configfiles : $tar_config_files_rc"); # print message
    		$tar_config_files=1; # set return number
   		} else { # tar was successfully
    		&verbose_print(msg_level=>2,message=>"successfully tared configfiles"); # print message
   		}
	} else {
		&verbose_print(msg_level=>2,message=>"there are no configfiles to be tared"); # print message
	}
   return $tar_config_files;
}

# sub for taring logfiles
sub tar_log_files(){
	my $tar_log_files=0;
	my $timestamp=`date +%s`;
	if (&count_files(folder=>$options{local_log_backupfolder},name=>$options{logfile_name}) > 0){
		my $tar_log_files_rc=system("/bin/tar --remove-files -cf $options{local_log_tarfolder}logs_$options{timestamp}.tar $options{local_log_backupfolder}$options{logfile_name}_*");
		if ($?) { # check if tar was successfull = 0, if failed rc = 1
    		chomp $tar_log_files_rc; # cut \n from return of copy command
    		&verbose_print(msg_level=>2,message=>"failed to tar the logfiles : $tar_log_files_rc"); # print message
    		$tar_log_files=1; # set return number
   		} else { # tar was successfully
    		&verbose_print(msg_level=>2,message=>"successfully tared logfiles"); # print message
   		}
	} else {
		&verbose_print(msg_level=>2,message=>"there are no logfiles to be tared"); # print message
	}
   return $tar_log_files;
}

# MAIN
my $script_rc=0;
unless ($script_rc > 0) { $script_rc=&check_cmdparameters;}
&verbose_print(msg_level=>0,message=>"starting script with $backup_type backup");
unless ($script_rc > 0) { $script_rc=&read_parameter_file;};
if ($flag_mount){
	unless ($script_rc > 0) { $script_rc=&mount_datadomain;}
} else {
	if (&check_mountpoint >0){
		&verbose_print(msg_level=>0,message=>"Datadomain not mounted !! -> aborting backup");
		exit 1;
	} else {&verbose_print(msg_level=>2,message=>"Datadomain is mounted");}
}
unless ($script_rc > 0) { $script_rc=&check_pathparameters;}
if (lc($backup_type) eq "db") {
	if (-e $options{lck_db_file}){ # check if lck_db_file exists (DB Backup is running) and abort if still there
	&verbose_print(msg_level=>0,message=>"DB-Backup already running -> if not, please delete $options{lck_db_file}");
	exit 1;
	}
	open (LCK,">$options{lck_db_file}") or die "could not open lck file $options{lck_db_file}\n"; # create db-lock file
	
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{remote_data_retention},filepath=>$options{remote_data_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{remote_data_retention},filepath=>$options{remote_config_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{local_data_retention},filepath=>$options{local_data_backupfolder},chk_copypath=>$options{remote_data_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{local_data_retention},filepath=>$options{local_config_backupfolder},chk_copypath=>$options{remote_config_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&check_db_os_size(chk_filepath=>$options{local_data_backupfolder})}
 unless ($script_rc > 0) { $script_rc=&backup_hana;}
 unless ($script_rc > 0) { $script_rc=&run_copy(source=>$options{local_data_backupfolder},destination=>$options{remote_data_backupfolder},command=>$options{how_to_copy});
				$script_rc.=&tar_config_files; 		
			    $script_rc.=&run_copy(source=>$options{local_config_backupfolder},destination=>$options{remote_config_backupfolder},command=>'cp');}
	close (LCK); # close db-lock file
	unlink $options{lck_db_file} if (-e $options{lck_db_file});
} elsif (lc($backup_type) eq "log") {
	if (-e $options{lck_log_file}){ # check if lck_log_file exists (LOG Backup is running) and abort if still there
	&verbose_print(msg_level=>0,message=>"LOG-Backup already running -> if not, please delete $options{lck_log_file}");
	exit 1;
	}
	open (LCK,">$options{lck_log_file}") or die "could not open lck file $options{lck_log_file}\n"; # create log-lock file
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{remote_log_retention},filepath=>$options{remote_log_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&delete_no_retention_files(retention=>$options{local_log_retention},filepath=>$options{local_log_tarfolder},chk_copypath=>$options{remote_log_backupfolder});}
 unless ($script_rc > 0) { $script_rc=&tar_log_files;
 	$script_rc.=&run_copy(source=>$options{local_log_tarfolder},destination=>$options{remote_log_backupfolder},command=>'cp');}
 	close (LCK); # close log-lock file
	unlink $options{lck_log_file} if (-e $options{lck_log_file});
} else {
 &verbose_print(msg_level=>0,message=>"backup type $backup_type is not supported"); # print message
}
if ($flag_mount){unless ($script_rc > 0) { $script_rc=&umount_datadomain;}}
&verbose_print(msg_level=>0,message=>"finished script backup $backup_type with RC: $script_rc\n".("#" x 20)."\n");
exit $script_rc;

__END__

=pod

=head1 VERSION

1.0

=head1 NAME

backup_hana.pl

=head1 DESCRIPTION

Script is for backup of a SAP HANA Database. It could be used to run a database backup (incl. catalog and config files) to a defined (local) directory and copy afterwards to a remote directory. Or for log backup with only a copy of local logfiles to a remote diretory (HANA DB automatically backup files to a folder). There is also a possibility to define a retention time for how long the data should be kept on each folder. For the correct work a configuration file with all path/filenames is necessary.

=head1 PREREQUISITE

A configuration file with following paramters must be available (key and value seperated by "="):

=over 4

MANDATORY:

=over 8

local folders of HANA config files and HANA backup catalog file

hana_config_folders   : folder names of hana config folders - multiple names are possible and have to be separated by comma (,)

hana_backup_catalog   : hana catalog filename   # this folder is not needed

local folder for destination of the backups (log is used as source folders)

local_data_backupfolder       : database datafile folder used as destination for database backup

local_config_backupfolder     : # database config backup folder used as destination for database backup

local_log_backupfolder        : database log folder - used as source for log backup

remote folders for backup used as copy destination

remote_data_backupfolder      : folder for database backup files

remote_config_backupfolder    : folder for config backup files

remote_log_backupfolder       : folder for log backup files

dd_mount_point			  : hana mount point for the system

=back

OPTIONAL:

=over 8

parameter for retention time of files and debug level

local_data_retention  : DEFAULT: 2    : retention of database files (incl. config,catalog) in days on local location

remote_data_retention : DEFAULT: 30   : retention of database files (incl. config,catalog) in days on remote location

local_log_retention   : DEFAULT: 30   : retention of log files in days on local location

remote_log_retention  : DEFAULT: 30   : retention of log files in days on remote location

debug : debug level to be used - 0-9

how_to_copy : command to use for transfering database to datadomain - default is dd - can be cp

=back

EXAMPLE:

=over 8

local_data_backupfolder = /hana/HMP/HDB00/backup/data

=back

=back

=head1 SYNOPSIS

backup_hana.pl -type [DB|LOG] {-configfile <filename>} {-debug <debuglevel>} {-mount}

backup_hana.pl -help

=head1 OPTIONS

=over 4

-type [DB|LOG]	- type of backup to do - DB = database backup | LOG = log backup

-configfile <filename>	- configurationfile that includes all necessary path/filenames; DEFUALT: /zuser/backup_hana.conf

-debug <debuglevel>	- debug level to be used at runtime; DEFAULT: 0

-mount	- flag used for mount and unmount datadomain mountpoint before/after backup

-help	- shows this message

=back

=cut
